using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static WaterCylinder.Resource;
/*
效果类，用于瞬时处理效果、暂时性的改变实体属性、实现一些Buff效果等。
注意效果类必需依附在实体上，对实体进行操作，所以务必保证Effect.entity不为空。
如果需要全局作用的效果，可以将效果依附在独立的全局实体上。

args属性用于指定参数，供事件调用时使用

*/

/// <summary>
/// 效果类型
/// </summary>
public enum EffectType{
    /// <summary>
    /// 瞬时效果
    /// </summary>
    Instant,
    /// <summary>
    /// 持续时间内作用效果
    /// </summary>
    Intime,
    /// <summary>
    /// 持续时间结束时作用效果
    /// </summary>
    EndTime,
    /// <summary>
    /// 永久效果
    /// </summary>
    Permanent,
}

/// <summary>
/// <para>Effect效果类，作用于实体类中，用于对实体类进行独立线程的操作。</para>
/// <para>效果运行在实体上，务必设置entity属性</para>
/// </summary>
[CreateAssetMenu(menuName = "Effect")]
public class Effect : ScriptableObject
{   
    
    /// <summary>
    /// 在实体上创建Effect效果
    /// </summary>
    /// <typeparam name="T">效果类形</typeparam>
    /// <returns></returns>
    public static Effect CreatEffect(ScriptableObject prefab){
        return Instantiate(prefab) as Effect;
    }

    public static Effect CreatEffect(string path){
        return CreatEffect(GetResources<ScriptableObject>("Effects/" + path));
    }

    public Coroutine process;

    #region 效果属性

    /// <summary>
    /// 目标实体
    /// </summary>
    public Entity entity;
    /// <summary>
    /// 效果类型
    /// </summary>
    public EffectType type;
    /// <summary>
    /// 效果ID
    /// </summary>
    public int id = 0;
    /// <summary>
    /// 效果图标
    /// </summary>
    public Sprite icon;
    /// <summary>
    /// 是否可重复
    /// </summary>
    public bool canRepeat = false;
    /// <summary>
    /// 是否可刷新状态,为true则实体重新获得同类效果时刷新效果
    /// </summary>
    public bool canFlash = true;
    [Tooltip("参数列表")]
    public List<int> args = new List<int>();
    
    #endregion

    #region 事件

    /// <summary>
    /// 效果开始时
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnEffectStart = new EffectEvent();
    /// <summary>
    /// 效果结束时
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnEffectEnd = new EffectEvent();
    /// <summary>
    /// 添加层数时。默认重置计时。
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnAddLayer = new EffectEvent();
    /// <summary>
    /// 移除层数时。默认重置计时。
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnRemoveLayer = new EffectEvent();
    /// <summary>
    /// 层数内操作
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnLayer = new EffectEvent();
    /// <summary>
    /// 计时内操作
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnTime = new EffectEvent();
    /// <summary>
    /// 计时结束时。默认减少一层
    /// </summary>
    [Tooltip("Event")]
    public EffectEvent OnTimeEnd = new EffectEvent();

    #endregion

    #region 层数和时间操作

    /// <summary>
    /// 最大层数
    /// </summary>
    [SerializeField]
    public float maxLayer = 1;
    /// <summary>
    /// 当前层数
    /// </summary>
    [SerializeField]
    private int layer;
    /// <summary>
    /// 设置当前层数
    /// </summary>
    /// <param name="layer"></param>
    public void SetLayer(int layer){
        if(layer > maxLayer){
            layer = (int)maxLayer;
        }else if(layer <= 0){
            End();//层数小于等于0时销毁
        }
        this.layer = layer;
        OnLayer?.Invoke(entity, this);
    }
    /// <summary>
    /// 添加一层效果
    /// </summary>
    public void AddLayer(){
        OnAddLayer?.Invoke(entity, this);
        SetTime(0);
        SetLayer(layer + 1);
    }
    /// <summary>
    /// 移除一层效果
    /// </summary>
    public void RemoveLayer(){
        OnRemoveLayer?.Invoke(entity, this);
        SetTime(0);
        SetLayer(layer - 1);
    }
    /// <summary>
    /// 获取当前层数
    /// </summary>
    /// <returns></returns>
    public int GetLayer(){
        return layer;
    }
    
    /// <summary>
    /// 每层持续时间
    /// </summary>
    public float maxTime = 10;
    /// <summary>
    /// 当前持续时间
    /// </summary>
    [SerializeField]
    private float time;
    /// <summary>
    /// 设置当前时间
    /// </summary>
    /// <param name="time"></param>
    public void SetTime(float time = 0){
        if(time > maxTime){
            OnTimeEnd?.Invoke(entity, this);
            RemoveLayer();
            time = 0;
        }else if(time < 0){
            time = 0;
        }
        this.time = time;
    }
    /// <summary>
    /// 增减当前时间
    /// </summary>
    /// <param name="time"></param>
    public void AddTime(float time){
        OnTime?.Invoke(entity, this);
        SetTime(this.time + time);
    }
    /// <summary>
    /// 获取当前时间
    /// </summary>
    /// <returns></returns>
    public float GetTime(){
        return time;
    }

    /// <summary>
    /// 是否暂停计时
    /// </summary>
    [SerializeField]
    private bool isPause = false;
    /// <summary>
    /// 切换暂停
    /// </summary>
    public void Pause(){
        isPause = !isPause;
    }
    /// <summary>
    /// 设置暂停
    /// </summary>
    /// <param name="p">是否暂停</param>
    public void Pause(bool p){
        isPause = p;
    }

    #endregion

    #region 方法

    public void Start(){
        OnEffectStart?.Invoke(entity, this);
        process = entity.StartCoroutine(_process());
    }
    //协程
    private float processTime = .1f;
    IEnumerator _process(){
        while(true){
            if(!isPause){
                AddTime(processTime);
            }
            yield return new WaitForSeconds(processTime);
        }
    }

    /// <summary>
    /// 调用该方法以结束Effect效果处理
    /// </summary>
    public void End(){
        OnEffectEnd?.Invoke(entity, this);
        entity.StopCoroutine(process);
        OnEffectStart.RemoveAllListeners();
        OnEffectEnd.RemoveAllListeners();
        OnTime.RemoveAllListeners();
        OnLayer.RemoveAllListeners();
        OnAddLayer.RemoveAllListeners();
        OnRemoveLayer.RemoveAllListeners();
        OnTimeEnd.RemoveAllListeners();
        entity.RemoveEffect(this);//在实体的效果列表中移除自己
        Destroy(this);
    }

    #endregion

}
